<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>字段映射配置生成器</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            background-color: #f5f7fa;
            color: #333;
            line-height: 1.6;
        }

        .container {
            max-width: 1400px;
            margin: 0 auto;
            padding: 20px;
        }

        .header {
            text-align: center;
            margin-bottom: 30px;
            background: white;
            padding: 30px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }

        .header h1 {
            color: #2c3e50;
            margin-bottom: 10px;
        }

        .header p {
            color: #7f8c8d;
            font-size: 16px;
        }

        .input-section {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 20px;
            margin-bottom: 30px;
        }

        .input-group {
            background: white;
            padding: 25px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }

        .input-group h3 {
            margin-bottom: 15px;
            color: #2c3e50;
            border-bottom: 2px solid #3498db;
            padding-bottom: 8px;
        }

        textarea {
            width: 100%;
            min-height: 200px;
            padding: 15px;
            border: 2px solid #ecf0f1;
            border-radius: 6px;
            font-family: 'Courier New', monospace;
            font-size: 14px;
            resize: vertical;
            transition: border-color 0.3s ease;
        }

        textarea:focus {
            outline: none;
            border-color: #3498db;
        }

        .table-name-input {
            width: 100%;
            padding: 12px;
            border: 2px solid #ecf0f1;
            border-radius: 6px;
            font-size: 16px;
            margin-bottom: 15px;
            transition: border-color 0.3s ease;
        }

        .table-name-input:focus {
            outline: none;
            border-color: #3498db;
        }

        .btn {
            background: linear-gradient(135deg, #3498db, #2980b9);
            color: white;
            border: none;
            padding: 12px 25px;
            border-radius: 6px;
            cursor: pointer;
            font-size: 16px;
            font-weight: 600;
            transition: all 0.3s ease;
            margin: 5px;
        }

        .btn:hover {
            transform: translateY(-2px);
            box-shadow: 0 4px 12px rgba(52, 152, 219, 0.3);
        }

        .btn-success {
            background: linear-gradient(135deg, #27ae60, #229954);
        }

        .btn-warning {
            background: linear-gradient(135deg, #f39c12, #e67e22);
        }

        .controls {
            text-align: center;
            margin-bottom: 30px;
        }

        .mapping-section {
            background: white;
            padding: 25px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            margin-bottom: 30px;
        }

        .mapping-table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 20px;
            table-layout: fixed; /* 固定表格布局以便精确控制列宽 */
        }

        .mapping-table th,
        .mapping-table td {
            padding: 8px 12px;
            text-align: left;
            border-bottom: 1px solid #ecf0f1;
            word-wrap: break-word;
            overflow-wrap: break-word;
        }

        .mapping-table th {
            background-color: #f8f9fa;
            font-weight: 600;
            color: #2c3e50;
            position: sticky;
            top: 0;
            z-index: 10;
        }

        /* 列宽度控制 */
        .mapping-table .col-field-name {
            width: 18%; /* 数据库字段名 */
        }

        .mapping-table .col-comment {
            width: 15%; /* 字段注释 - 缩小 */
        }

        .mapping-table .col-api-path {
            width: 45%; /* API路径 - 大幅增加 */
        }

        .mapping-table .col-status {
            width: 10%; /* 状态 */
        }

        .mapping-table .col-actions {
            width: 12%; /* 操作 */
        }

        .mapping-table tr:hover {
            background-color: #f8f9fa;
        }

        .field-input {
            width: 100%;
            padding: 6px 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
            font-family: 'Courier New', monospace;
            font-size: 12px;
            line-height: 1.4;
            transition: all 0.2s ease;
        }

        .field-input:focus {
            outline: none;
            border-color: #3498db;
            background-color: #f8f9fa;
            box-shadow: 0 0 0 2px rgba(52, 152, 219, 0.1);
        }

        .field-input::placeholder {
            color: #999;
            font-size: 11px;
        }

        .status-badge {
            display: inline-block;
            padding: 4px 8px;
            border-radius: 12px;
            font-size: 12px;
            font-weight: 600;
        }

        .status-matched {
            background-color: #d4edda;
            color: #155724;
        }

        .status-manual {
            background-color: #fff3cd;
            color: #856404;
        }

        .status-empty {
            background-color: #f8d7da;
            color: #721c24;
        }

        .output-section {
            background: white;
            padding: 25px;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }

        .output-section h3 {
            margin-bottom: 15px;
            color: #2c3e50;
            border-bottom: 2px solid #27ae60;
            padding-bottom: 8px;
        }

        .yaml-output {
            background-color: #2c3e50;
            color: #ecf0f1;
            padding: 20px;
            border-radius: 6px;
            font-family: 'Courier New', monospace;
            font-size: 14px;
            white-space: pre-wrap;
            max-height: 400px;
            overflow-y: auto;
            border: none;
            resize: vertical;
        }

        .copy-btn {
            margin-top: 10px;
        }

        .api-structure {
            max-height: 300px;
            overflow-y: auto;
            background-color: #f8f9fa;
            padding: 15px;
            border-radius: 6px;
            margin-top: 10px;
            font-family: 'Courier New', monospace;
            font-size: 12px;
            white-space: pre-wrap;
        }

        .search-box {
            width: 100%;
            padding: 10px;
            border: 2px solid #ecf0f1;
            border-radius: 6px;
            margin-bottom: 15px;
            font-size: 14px;
        }

        .search-box:focus {
            outline: none;
            border-color: #3498db;
        }

        .stats {
            display: flex;
            justify-content: space-around;
            margin: 20px 0;
            background: #f8f9fa;
            padding: 15px;
            border-radius: 6px;
        }

        .stat-item {
            text-align: center;
        }

        .stat-number {
            font-size: 24px;
            font-weight: bold;
            color: #2c3e50;
        }

        .stat-label {
            font-size: 14px;
            color: #7f8c8d;
        }

        .error-message {
            background-color: #f8d7da;
            color: #721c24;
            padding: 12px;
            border-radius: 6px;
            margin: 10px 0;
            border: 1px solid #f5c6cb;
        }

        .success-message {
            background-color: #d4edda;
            color: #155724;
            padding: 12px;
            border-radius: 6px;
            margin: 10px 0;
            border: 1px solid #c3e6cb;
        }

        .help-text {
            font-size: 14px;
            color: #6c757d;
            margin-top: 10px;
            line-height: 1.5;
        }

        @media (max-width: 768px) {
            .input-section {
                grid-template-columns: 1fr;
            }
            
            .container {
                padding: 10px;
            }

            /* 移动端表格优化 */
            .mapping-table .col-field-name {
                width: 20%;
            }

            .mapping-table .col-comment {
                width: 12%;
            }

            .mapping-table .col-api-path {
                width: 48%;
            }

            .mapping-table .col-status {
                width: 8%;
            }

            .mapping-table .col-actions {
                width: 12%;
            }

            .field-input {
                font-size: 11px;
                padding: 4px 6px;
            }

            .status-badge {
                font-size: 10px;
                padding: 2px 6px;
            }
        }

        @media (max-width: 480px) {
            /* 超小屏幕优化 */
            .mapping-table .col-comment {
                display: none; /* 隐藏注释列 */
            }

            .mapping-table .col-field-name {
                width: 25%;
            }

            .mapping-table .col-api-path {
                width: 55%;
            }

            .mapping-table .col-status {
                width: 10%;
            }

            .mapping-table .col-actions {
                width: 10%;
            }
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>字段映射配置生成器</h1>
            <p>快速生成数据库表与API响应的字段映射YAML配置</p>
        </div>

        <div class="input-section">
            <div class="input-group">
                <h3>数据库表结构 (DDL)</h3>
                <input type="text" class="table-name-input" id="tableName" placeholder="请输入表名，如：bjhl_property_transfer">
                <textarea id="ddlInput" placeholder="请粘贴CREATE TABLE语句...

例如：
CREATE TABLE `bjhl_property_transfer` (
  `id` BIGINT AUTO_INCREMENT PRIMARY KEY COMMENT '主键ID',
  `project_name` TEXT COMMENT '项目名称',
  `project_code` VARCHAR(100) COMMENT '项目编号',
  ...
);"></textarea>
                <div class="help-text">
                    支持标准的MySQL CREATE TABLE语句，系统会自动解析字段名和注释
                </div>
            </div>

            <div class="input-group">
                <h3>API响应数据</h3>
                <textarea id="apiInput" placeholder="请粘贴API响应JSON数据...

例如：
{
  &quot;data&quot;: {
    &quot;list&quot;: [{
      &quot;id&quot;: &quot;123&quot;,
      &quot;projectName&quot;: &quot;项目名称&quot;,
      &quot;detail&quot;: {
        &quot;object_name&quot;: &quot;标的名称&quot;
      }
    }]
  }
}"></textarea>
                <div class="help-text">
                    粘贴完整的API响应JSON，系统会自动分析数据结构和可用字段路径
                </div>
            </div>
        </div>

        <div class="controls">
            <button class="btn" onclick="parseInputs()">解析并生成映射</button>
            <button class="btn btn-warning" onclick="autoMatch()" title="使用智能算法自动匹配字段">🧠 智能自动匹配</button>
            <button class="btn btn-success" onclick="generateYaml()">生成YAML配置</button>
        </div>

        <div style="background: #e3f2fd; padding: 15px; border-radius: 6px; margin-bottom: 20px; font-size: 14px;">
            <h4 style="margin-bottom: 10px; color: #1976d2;">🧠 智能匹配算法说明</h4>
            <p><strong>优化的匹配策略（按优先级排序）：</strong></p>
            <ul style="margin: 10px 0; padding-left: 20px;">
                <li><strong>🎯 精确匹配：</strong> 优先匹配完全相同的字段名（px_department_head → px_department_head）</li>
                <li><strong>📐 长度感知：</strong> 长度相近的字段优先级更高，避免匹配到过长的字段</li>
                <li><strong>🔄 驼峰转换：</strong> project_code ↔ projectCode 自动识别并匹配</li>
                <li><strong>🧠 语义映射：</strong> project_label ↔ labels，track_tags ↔ tracks 等语义相关字段</li>
                <li><strong>🔍 模糊匹配：</strong> 使用编辑距离算法匹配拼写相近的字段</li>
                <li><strong>⚖️ 智能评分：</strong> 综合长度差异、语义相似度等因素，确保最佳匹配</li>
            </ul>
            <p><strong>路径格式：</strong> 生成的路径包含完整的API响应结构（如 data.list[].projectName），数据处理器会自动标准化这些路径。</p>
        </div>

        <div id="mappingSection" class="mapping-section" style="display: none;">
            <h3>字段映射配置</h3>
            <div class="stats">
                <div class="stat-item">
                    <div class="stat-number" id="totalFields">0</div>
                    <div class="stat-label">总字段数</div>
                </div>
                <div class="stat-item">
                    <div class="stat-number" id="matchedFields">0</div>
                    <div class="stat-label">已匹配</div>
                </div>
                <div class="stat-item">
                    <div class="stat-number" id="emptyFields">0</div>
                    <div class="stat-label">未配置</div>
                </div>
            </div>
            
            <input type="text" class="search-box" id="searchBox" placeholder="搜索字段名..." onkeyup="filterTable()">
            
            <div style="max-height: 500px; overflow-y: auto;">
                <table class="mapping-table" id="mappingTable">
                    <thead>
                        <tr>
                            <th class="col-field-name">数据库字段</th>
                            <th class="col-comment">字段注释</th>
                            <th class="col-api-path">API路径</th>
                            <th class="col-status">状态</th>
                            <th class="col-actions">操作</th>
                        </tr>
                    </thead>
                    <tbody id="mappingTableBody">
                    </tbody>
                </table>
            </div>

            <div style="margin-top: 20px;">
                <h4>API数据结构参考</h4>
                <div id="apiStructure" class="api-structure"></div>
            </div>
        </div>

        <div id="outputSection" class="output-section" style="display: none;">
            <h3>生成的YAML配置</h3>
            <textarea class="yaml-output" id="yamlOutput" readonly></textarea>
            <button class="btn copy-btn" onclick="copyYaml()">复制YAML</button>
            <div class="help-text">
                复制此YAML配置到你的config.yaml文件的field_mapping部分
            </div>
        </div>
    </div>

    <script>
        let dbFields = [];
        let apiStructure = {};
        let apiPaths = [];

        function parseInputs() {
            const tableName = document.getElementById('tableName').value.trim();
            const ddlText = document.getElementById('ddlInput').value.trim();
            const apiText = document.getElementById('apiInput').value.trim();

            if (!tableName) {
                showError('请输入表名');
                return;
            }

            if (!ddlText) {
                showError('请输入DDL语句');
                return;
            }

            if (!apiText) {
                showError('请输入API响应数据');
                return;
            }

            try {
                // 解析DDL
                dbFields = parseDDL(ddlText);
                showSuccess(`解析到 ${dbFields.length} 个数据库字段`);

                // 解析API结构
                const apiData = JSON.parse(apiText);
                apiStructure = apiData;
                apiPaths = extractApiPaths(apiData);
                showSuccess(`解析到 ${apiPaths.length} 个API字段路径`);

                // 显示映射表格
                buildMappingTable();
                updateApiStructureDisplay();
                
                document.getElementById('mappingSection').style.display = 'block';
                
            } catch (error) {
                showError('解析失败: ' + error.message);
            }
        }

        function parseDDL(ddlText) {
            const fields = [];
            const lines = ddlText.split('\n');
            
            for (let line of lines) {
                line = line.trim();
                if (line.startsWith('`') && line.includes('COMMENT')) {
                    const match = line.match(/`([^`]+)`[^']*COMMENT\s*'([^']*)'/);
                    if (match) {
                        const fieldName = match[1];
                        const comment = match[2];
                        
                        // 排除主键和时间戳字段
                        if (!['id', 'created_at', 'updated_at'].includes(fieldName)) {
                            fields.push({
                                name: fieldName,
                                comment: comment,
                                apiPath: '',
                                status: 'empty'
                            });
                        }
                    }
                }
            }
            
            return fields;
        }

        function extractApiPaths(obj, prefix = '', paths = []) {
            if (obj === null || obj === undefined) {
                return paths;
            }

            if (typeof obj === 'object') {
                if (Array.isArray(obj)) {
                    if (obj.length > 0) {
                        // 数组路径
                        paths.push(prefix + '[]');
                        // 数组元素的子路径
                        extractApiPaths(obj[0], prefix + '[]', paths);
                        // 数组索引访问
                        paths.push(prefix + '[0]');
                        extractApiPaths(obj[0], prefix + '[0].', paths);
                    }
                } else {
                    // 对象路径
                    for (let key in obj) {
                        const newPrefix = prefix ? prefix + '.' + key : key;
                        paths.push(newPrefix);
                        extractApiPaths(obj[key], newPrefix, paths);
                    }
                }
            }

            return paths;
        }

        function buildMappingTable() {
            const tbody = document.getElementById('mappingTableBody');
            tbody.innerHTML = '';

            dbFields.forEach((field, index) => {
                const row = document.createElement('tr');
                row.innerHTML = `
                    <td class="col-field-name"><strong>${field.name}</strong></td>
                    <td class="col-comment">
                        <span style="color: #6c757d; font-size: 13px; line-height: 1.3;">${field.comment}</span>
                    </td>
                    <td class="col-api-path">
                        <input type="text" class="field-input" 
                               value="${field.apiPath}" 
                               onchange="updateFieldPath(${index}, this.value)"
                               placeholder="例如: projectName, detail.object_name, labels[0].track_tags"
                               style="width: 100%; min-width: 200px;">
                    </td>
                    <td class="col-status">
                        <span class="status-badge status-${field.status}">${getStatusText(field.status)}</span>
                    </td>
                    <td class="col-actions">
                        <button class="btn" style="padding: 4px 8px; font-size: 11px; margin: 1px;" onclick="suggestPaths(${index})">建议</button>
                        <button class="btn btn-warning" style="padding: 4px 8px; font-size: 11px; margin: 1px;" onclick="clearField(${index})">清空</button>
                    </td>
                `;
                tbody.appendChild(row);
            });

            updateStats();
        }

        function updateFieldPath(index, value) {
            dbFields[index].apiPath = value.trim();
            dbFields[index].status = value.trim() ? 'manual' : 'empty';
            updateRowStatus(index);
            updateStats();
        }

        function updateRowStatus(index) {
            const row = document.querySelector(`#mappingTableBody tr:nth-child(${index + 1})`);
            const statusBadge = row.querySelector('.status-badge');
            const field = dbFields[index];
            
            statusBadge.className = `status-badge status-${field.status}`;
            statusBadge.textContent = getStatusText(field.status);
        }

        function getStatusText(status) {
            switch (status) {
                case 'matched': return '自动匹配';
                case 'manual': return '手动配置';
                case 'empty': return '未配置';
                default: return '未知';
            }
        }

        function autoMatch() {
            let matchedCount = 0;
            
            dbFields.forEach((field, index) => {
                // 尝试直接匹配字段名
                let bestMatch = findBestMatch(field.name);
                
                if (bestMatch) {
                    field.apiPath = bestMatch;
                    field.status = 'matched';
                    matchedCount++;
                }
            });

            buildMappingTable();
            showSuccess(`自动匹配了 ${matchedCount} 个字段`);
        }

        function findBestMatch(fieldName) {
            // 1. 直接匹配
            if (apiPaths.includes(fieldName)) {
                return fieldName;
            }

            // 2. 驼峰式匹配
            const camelCase = toCamelCase(fieldName);
            if (apiPaths.includes(camelCase)) {
                return camelCase;
            }

            // 3. 在detail中查找精确匹配
            const detailPath = 'detail.' + fieldName;
            if (apiPaths.includes(detailPath)) {
                return detailPath;
            }

            const detailCamelPath = 'detail.' + camelCase;
            if (apiPaths.includes(detailCamelPath)) {
                return detailCamelPath;
            }

            // 4. 精确字段名匹配（忽略路径前缀）
            const normalizedField = normalizeFieldName(fieldName);
            const exactMatches = apiPaths.filter(path => {
                const apiFieldName = getFieldNameFromPath(path);
                const normalizedApi = normalizeFieldName(apiFieldName);
                return normalizedField === normalizedApi;
            });
            
            if (exactMatches.length > 0) {
                // 如果有多个精确匹配，优先选择路径最短的（通常是最直接的）
                exactMatches.sort((a, b) => a.length - b.length);
                return exactMatches[0];
            }

            // 5. 智能模糊匹配
            const bestMatch = findFuzzyMatch(fieldName);
            return bestMatch;
        }

        function findFuzzyMatch(fieldName) {
            const normalizedField = normalizeFieldName(fieldName);
            let bestMatches = [];

            // 计算所有路径的匹配得分
            apiPaths.forEach(path => {
                const score = calculateMatchScore(normalizedField, path, fieldName);
                if (score > 0) {
                    bestMatches.push({ path, score });
                }
            });

            // 按得分排序，返回最佳匹配
            bestMatches.sort((a, b) => b.score - a.score);
            
            // 返回得分最高且超过阈值的匹配
            if (bestMatches.length > 0 && bestMatches[0].score >= 0.6) {
                return bestMatches[0].path;
            }

            return '';
        }

        function normalizeFieldName(fieldName) {
            // 移除特殊符号，保留英文数字，转小写
            return fieldName.replace(/[_\-\s]/g, '').replace(/[^a-zA-Z0-9]/g, '').toLowerCase();
        }

        function getFieldNameFromPath(path) {
            // 提取路径的最后一部分作为字段名
            return path.split('.').pop().split('[')[0];
        }

        function calculateMatchScore(normalizedField, apiPath, originalField) {
            const apiFieldName = getFieldNameFromPath(apiPath);
            const normalizedApi = normalizeFieldName(apiFieldName);
            
            let score = 0;

            // 1. 完全匹配 (最高分) - 提高完全匹配的权重
            if (normalizedField === normalizedApi) {
                score = 1.0;
            }
            // 2. 精确匹配 - 字段长度基本一致的匹配
            else if (normalizedField.includes(normalizedApi) || normalizedApi.includes(normalizedField)) {
                // 计算长度差异，优先选择长度相近的字段
                const lengthDiff = Math.abs(normalizedField.length - normalizedApi.length);
                const maxLength = Math.max(normalizedField.length, normalizedApi.length);
                const lengthRatio = lengthDiff / maxLength;
                
                // 长度越相近，得分越高
                if (lengthRatio <= 0.1) {
                    // 长度差异10%以内，认为是精确匹配
                    score = 0.95;
                } else if (lengthRatio <= 0.3) {
                    // 长度差异30%以内，较高匹配
                    score = 0.85;
                } else {
                    // 长度差异较大，普通包含匹配
                    score = 0.7;
                }
                
                // 如果较短的字段是较长字段的开头/结尾，额外加分
                if (normalizedField.length < normalizedApi.length) {
                    if (normalizedApi.startsWith(normalizedField) || normalizedApi.endsWith(normalizedField)) {
                        score += 0.05;
                    }
                } else if (normalizedApi.length < normalizedField.length) {
                    if (normalizedField.startsWith(normalizedApi) || normalizedField.endsWith(normalizedApi)) {
                        score += 0.05;
                    }
                }
            }
            // 3. 语义相似匹配 (特殊规则)
            else {
                score = calculateSemanticSimilarity(normalizedField, normalizedApi, originalField, apiFieldName);
            }

            // 4. 路径权重加成 - 减少权重避免影响主要匹配逻辑
            if (apiPath.startsWith('detail.')) {
                score += 0.02; // detail路径小幅加分
            }
            
            // 5. 数组路径处理
            if (apiPath.includes('[]')) {
                score += 0.01; // 数组路径小幅加分
            }

            // 6. 字段名完全相同的特殊处理 (去除下划线后)
            const originalNormalized = normalizeFieldName(originalField);
            const apiOriginalNormalized = normalizeFieldName(apiFieldName);
            if (originalNormalized === apiOriginalNormalized) {
                score = Math.max(score, 0.98); // 确保原始字段名相同时得到高分
            }

            // 7. 长度惩罚 - 对长度差异过大的匹配进行惩罚
            const lengthSimilarity = 1 - Math.abs(normalizedField.length - normalizedApi.length) / Math.max(normalizedField.length, normalizedApi.length);
            if (lengthSimilarity < 0.5) {
                score *= 0.8; // 长度差异过大时降低得分
            }

            return Math.min(score, 1.0); // 确保不超过1.0
        }

        function calculateSemanticSimilarity(normalizedField, normalizedApi, originalField, apiFieldName) {
            // 语义映射规则
            const semanticMappings = {
                // // 标签相关
                // 'projectlabel': ['labels', 'label', 'tag', 'tags'],
                // 'tracktags': ['labels', 'tracks', 'track'],
                // 'trendingtags': ['labels', 'trending', 'trend'],
                // 'listedtags': ['labels', 'listed', 'list'],
                
                // 项目相关
                'projectname': ['name', 'title', 'projecttitle'],
                'projectcode': ['code', 'num', 'number', 'id'],
                'projecttype': ['type', 'category', 'kind'],
                'projectstate': ['state', 'status', 'condition'],
                
                // 时间相关
                'dicstart': ['start', 'begin', 'from', 'startdate', 'starttime'],
                'dicend': ['end', 'finish', 'to', 'enddate', 'endtime'],
                'registerdate': ['date', 'time', 'created', 'register'],
                'ratifydate': ['date', 'time', 'ratify', 'approve'],
                
                // 业务相关
                'bizsys': ['biz', 'business', 'system', 'sys'],
                'isdelete': ['delete', 'deleted', 'remove', 'removed'],
                'objectname': ['name', 'object', 'target', 'subject'],
                
                // 组织相关
                'organizationname': ['organization', 'org', 'company', 'institution'],
                'organizationcontactnumber': ['contact', 'phone', 'tel', 'number'],
                'organizationlinkman': ['linkman', 'contact', 'person', 'man'],
                
                // 转让方相关
                'transferorname': ['name', 'transferor', 'seller'],
                'transferorregistrationplace': ['place', 'address', 'location', 'registration'],
                'transferoreconomictype': ['type', 'economic', 'category'],
                
                // 股东相关
                'shareholdername': ['name', 'shareholder', 'holder'],
                'proportion': ['ratio', 'percent', 'share', 'proportion'],
                'shareholdingratio': ['ratio', 'proportion', 'share', 'holding'],
                
                // 审计相关
                'audityear': ['year', 'audit', 'annual'],
                'auditearning': ['earning', 'income', 'revenue'],
                'auditprofit': ['profit', 'earnings', 'income'],
                'auditasset': ['asset', 'assets', 'total'],
                'auditdebt': ['debt', 'liability', 'liabilities'],
                
                // 财务报表相关
                'stmtdate': ['date', 'statement', 'stmt'],
                'stmtearning': ['earning', 'income', 'revenue'],
                'stmtprofit': ['profit', 'earnings'],
                'stmtasset': ['asset', 'assets'],
                'stmtdebt': ['debt', 'liability']
            };

            // 检查语义映射
            if (semanticMappings[normalizedField]) {
                for (let synonym of semanticMappings[normalizedField]) {
                    if (normalizedApi.includes(synonym) || synonym.includes(normalizedApi)) {
                        return 0.8;
                    }
                }
            }

            // 反向检查
            for (let [key, synonyms] of Object.entries(semanticMappings)) {
                if (synonyms.includes(normalizedApi) && normalizedField.includes(key.substring(0, Math.min(key.length, 6)))) {
                    return 0.8;
                }
            }

            // 编辑距离相似度 (适用于拼写相近的词)
            const editDistance = calculateEditDistance(normalizedField, normalizedApi);
            const maxLength = Math.max(normalizedField.length, normalizedApi.length);
            const similarity = 1 - editDistance / maxLength;
            
            // 只有相似度足够高才认为是匹配
            if (similarity >= 0.7) {
                return similarity * 0.7;
            }

            // 子串匹配 (更宽松的匹配)
            if (normalizedField.length >= 4 && normalizedApi.length >= 4) {
                const commonSubstring = findLongestCommonSubstring(normalizedField, normalizedApi);
                if (commonSubstring.length >= 4) {
                    return (commonSubstring.length / Math.max(normalizedField.length, normalizedApi.length)) * 0.6;
                }
            }

            return 0;
        }

        function calculateEditDistance(str1, str2) {
            const matrix = [];
            const len1 = str1.length;
            const len2 = str2.length;

            for (let i = 0; i <= len2; i++) {
                matrix[i] = [i];
            }

            for (let j = 0; j <= len1; j++) {
                matrix[0][j] = j;
            }

            for (let i = 1; i <= len2; i++) {
                for (let j = 1; j <= len1; j++) {
                    if (str2.charAt(i - 1) === str1.charAt(j - 1)) {
                        matrix[i][j] = matrix[i - 1][j - 1];
                    } else {
                        matrix[i][j] = Math.min(
                            matrix[i - 1][j - 1] + 1,
                            matrix[i][j - 1] + 1,
                            matrix[i - 1][j] + 1
                        );
                    }
                }
            }

            return matrix[len2][len1];
        }

        function findLongestCommonSubstring(str1, str2) {
            let longest = '';
            for (let i = 0; i < str1.length; i++) {
                for (let j = i + 1; j <= str1.length; j++) {
                    const substring = str1.slice(i, j);
                    if (str2.includes(substring) && substring.length > longest.length) {
                        longest = substring;
                    }
                }
            }
            return longest;
        }

        function toCamelCase(str) {
            return str.replace(/_([a-z])/g, (match, letter) => letter.toUpperCase());
        }

        function suggestPaths(index) {
            const field = dbFields[index];
            const fieldName = field.name;
            const normalizedField = normalizeFieldName(fieldName);
            
            let suggestions = [];

            // 使用智能模糊匹配算法生成建议
            apiPaths.forEach(path => {
                const score = calculateMatchScore(normalizedField, path, fieldName);
                if (score > 0.4) { // 降低阈值以显示更多建议
                    suggestions.push({ 
                        path, 
                        score, 
                        reason: getMatchReason(normalizedField, path, fieldName, score)
                    });
                }
            });

            // 按得分排序
            suggestions.sort((a, b) => b.score - a.score);
            
            // 限制建议数量
            suggestions = suggestions.slice(0, 5);

            if (suggestions.length > 0) {
                let message = `为字段 "${fieldName}" 找到以下匹配建议：\n\n`;
                suggestions.forEach((suggestion, i) => {
                    message += `${i + 1}. ${suggestion.path} (得分: ${(suggestion.score * 100).toFixed(1)}%)\n`;
                    message += `   ${suggestion.reason}\n\n`;
                });
                message += `选择要应用的建议（输入1-${suggestions.length}），或按取消：`;

                const choice = prompt(message);
                const choiceIndex = parseInt(choice) - 1;
                
                if (choice && choiceIndex >= 0 && choiceIndex < suggestions.length) {
                    updateFieldPath(index, suggestions[choiceIndex].path);
                    buildMappingTable();
                    showSuccess(`已应用建议：${suggestions[choiceIndex].path}`);
                }
            } else {
                alert(`未找到字段 "${fieldName}" 的相关API路径建议\n\n请尝试手动输入路径，支持格式：\n- 简单字段：fieldName\n- 嵌套字段：detail.fieldName\n- JSON数组：labels[0].track_tags\n- 数组展开：detail.array[].field`);
            }
        }

        function getMatchReason(normalizedField, apiPath, originalField, score) {
            const apiFieldName = getFieldNameFromPath(apiPath);
            const normalizedApi = normalizeFieldName(apiFieldName);
            
            if (normalizedField === normalizedApi) {
                return "完全匹配";
            } else if (normalizedField.includes(normalizedApi) || normalizedApi.includes(normalizedField)) {
                return "包含匹配";
            } else if (score >= 0.8) {
                return "语义相似匹配";
            } else if (score >= 0.7) {
                return "高相似度匹配";
            } else if (score >= 0.6) {
                return "中等相似度匹配";
            } else {
                return "低相似度匹配";
            }
        }

        function clearField(index) {
            updateFieldPath(index, '');
            buildMappingTable();
        }

        function filterTable() {
            const searchTerm = document.getElementById('searchBox').value.toLowerCase();
            const rows = document.querySelectorAll('#mappingTableBody tr');

            rows.forEach(row => {
                const fieldName = row.cells[0].textContent.toLowerCase();
                const comment = row.cells[1].textContent.toLowerCase();
                const apiPath = row.cells[2].querySelector('input').value.toLowerCase();

                if (fieldName.includes(searchTerm) || comment.includes(searchTerm) || apiPath.includes(searchTerm)) {
                    row.style.display = '';
                } else {
                    row.style.display = 'none';
                }
            });
        }

        function updateStats() {
            const total = dbFields.length;
            const matched = dbFields.filter(f => f.status === 'matched').length;
            const manual = dbFields.filter(f => f.status === 'manual').length;
            const empty = dbFields.filter(f => f.status === 'empty').length;

            document.getElementById('totalFields').textContent = total;
            document.getElementById('matchedFields').textContent = matched + manual;
            document.getElementById('emptyFields').textContent = empty;
        }

        function updateApiStructureDisplay() {
            const container = document.getElementById('apiStructure');
            container.textContent = JSON.stringify(apiStructure, null, 2);
        }

        function generateYaml() {
            const tableName = document.getElementById('tableName').value.trim();
            
            if (!tableName) {
                showError('请输入表名');
                return;
            }

            const yamlLines = [
                `  ${tableName}:`,
                `    # 字段映射（数据库字段名 -> API字段路径）`,
                `    fields:`
            ];

            // 添加有映射的字段
            const mappedFields = dbFields.filter(f => f.apiPath.trim());
            mappedFields.forEach(field => {
                yamlLines.push(`      ${field.name}: "${field.apiPath}"`);
            });

            // 添加未映射的字段作为注释
            const unmappedFields = dbFields.filter(f => !f.apiPath.trim());
            if (unmappedFields.length > 0) {
                yamlLines.push('      # 未映射字段（请手动配置）：');
                unmappedFields.forEach(field => {
                    yamlLines.push(`      # ${field.name}: ""`);
                });
            }

            const yamlContent = yamlLines.join('\n');
            document.getElementById('yamlOutput').value = yamlContent;
            document.getElementById('outputSection').style.display = 'block';

            showSuccess(`生成了包含 ${mappedFields.length} 个字段映射的YAML配置`);
        }

        function copyYaml() {
            const yamlOutput = document.getElementById('yamlOutput');
            yamlOutput.select();
            document.execCommand('copy');
            showSuccess('YAML配置已复制到剪贴板');
        }

        function showError(message) {
            const container = document.querySelector('.container');
            const existing = container.querySelector('.error-message');
            if (existing) existing.remove();

            const errorDiv = document.createElement('div');
            errorDiv.className = 'error-message';
            errorDiv.textContent = message;
            container.insertBefore(errorDiv, container.firstChild);
            
            setTimeout(() => errorDiv.remove(), 5000);
        }

        function showSuccess(message) {
            const container = document.querySelector('.container');
            const existing = container.querySelector('.success-message');
            if (existing) existing.remove();

            const successDiv = document.createElement('div');
            successDiv.className = 'success-message';
            successDiv.textContent = message;
            container.insertBefore(successDiv, container.firstChild);
            
            setTimeout(() => successDiv.remove(), 3000);
        }

        // 页面加载时的示例数据
        window.onload = function() {
            // 可以在这里添加一些示例数据
            document.getElementById('tableName').value = 'bjhl_property_transfer';
        };
    </script>
</body>
</html>
